//
// Created by zhouwd on 2019/7/5.
//

#include <unistd.h>
#include "media-record.h"
static int64_t getCurrentTime()      //直接调用这个函数就行了，返回值最好是int64_t，long long应该也可以
{
    timespec now;
    clock_gettime(CLOCK_MONOTONIC, &now);
    return (now.tv_sec * 1000000000LL + now.tv_nsec) / 1000;
}


//FILE* videoFile;

//FILE* voiceFile;

int _MEDIA_RECORD::init(int fd) {


    muxer = AMediaMuxer_new(fd, AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4);

    AMediaFormat *audioFormat = AMediaFormat_new();

    AMediaFormat_setString(audioFormat, AMEDIAFORMAT_KEY_MIME, "audio/mp4a-latm");
    AMediaFormat_setInt32(audioFormat, AMEDIAFORMAT_KEY_SAMPLE_RATE, 44100);
    AMediaFormat_setInt32(audioFormat, AMEDIAFORMAT_KEY_CHANNEL_COUNT, 1);
    AMediaFormat_setInt32(audioFormat, AMEDIAFORMAT_KEY_BIT_RATE, 64000); // 帧率
    AMediaFormat_setInt32(audioFormat, AMEDIAFORMAT_KEY_AAC_PROFILE, 2); // 编码质量

    AMediaFormat *videoFormat = AMediaFormat_new();

    AMediaFormat_setString(videoFormat, AMEDIAFORMAT_KEY_MIME, "video/avc");
    AMediaFormat_setInt32(videoFormat, AMEDIAFORMAT_KEY_BIT_RATE, 3500000);
    AMediaFormat_setInt32(videoFormat, AMEDIAFORMAT_KEY_FRAME_RATE, 30);
    AMediaFormat_setInt32(videoFormat, AMEDIAFORMAT_KEY_WIDTH, 720); // 视频宽度
    AMediaFormat_setInt32(videoFormat, AMEDIAFORMAT_KEY_HEIGHT, 1280); // 视频高度
    AMediaFormat_setInt32(videoFormat, AMEDIAFORMAT_KEY_COLOR_FORMAT, 21);
    AMediaFormat_setInt32(videoFormat, AMEDIAFORMAT_KEY_I_FRAME_INTERVAL, 1);

    audioCodec = AMediaCodec_createEncoderByType("audio/mp4a-latm");

    if (audioCodec == NULL) {

        return -1;
    }

    audioPresentationTimeUs = getCurrentTime();

    media_status_t audioRc = AMediaCodec_configure(audioCodec, audioFormat, NULL, NULL, AMEDIACODEC_CONFIGURE_FLAG_ENCODE);

    if (audioRc != AMEDIA_OK ) {

        AMediaCodec_delete(audioCodec);

        return audioRc;
    }

    videoPresentationTimeUs = getCurrentTime();

    ALOGE("media_record ---> init --->videoPresentationTimeUs >> %lld", videoPresentationTimeUs);

    videoCodec = AMediaCodec_createEncoderByType("video/avc");

    if (videoCodec == NULL) {
        return -2;
    }

    media_status_t videoRc = AMediaCodec_configure(videoCodec, videoFormat, NULL, NULL, AMEDIACODEC_CONFIGURE_FLAG_ENCODE);

    if (videoRc != AMEDIA_OK ) {
        AMediaCodec_delete(videoCodec);
        return videoRc;
    }

    media_status_t videoCodecStatus = AMediaCodec_start(videoCodec);
    ALOGE("media_record ---> init --->videoCodecStatus >> %d", videoCodecStatus );
    media_status_t audioCodecStatus =AMediaCodec_start(audioCodec);
    ALOGE("media_record ---> init --->audioCodecStatus >> %d", audioCodecStatus );

    return 0;
}

int _MEDIA_RECORD::encodeVideoData(char *data, size_t buf_size) {

    if (!status) {
        //ALOGE("inputEncodeBuffer >>>> encodeVideoData");
        return -1;
    }

    ssize_t bufidxInput = AMediaCodec_dequeueInputBuffer(videoCodec, -1);
    //ALOGE("inputEncodeBuffer >>>> %d", bufidx);
    if (bufidxInput >= 0) {
        // 获取buffer的索引
        size_t out_size;

        uint8_t *inputBuf = AMediaCodec_getInputBuffer(videoCodec, bufidxInput, &out_size);
        if (inputBuf != nullptr && buf_size <= out_size) {
            // 将待解码的数据copy到硬件中
            memcpy(inputBuf, data, buf_size);

            int64_t currentTime = getCurrentTime();
            //ALOGE("videoPresentationTimeUs >>>> %lld >> currentTime >> %lld", videoPresentationTimeUs, currentTime);
            int64_t pts = currentTime - videoPresentationTimeUs;

            media_status_t status = AMediaCodec_queueInputBuffer(videoCodec, bufidxInput, 0, buf_size, pts,0);
            //ALOGE("status >>>> %d >> pts >> %lld", status, pts);
        }
    }


    return 0;
}

int _MEDIA_RECORD::encodeAudioData(char *data, size_t buf_size) {

    if (!status) {
        //ALOGE("inputEncodeBuffer >>>> encodeAudioData");
        return -1;
    }

    ssize_t bufidxInput = AMediaCodec_dequeueInputBuffer(audioCodec, -1);
    //ALOGE("inputEncodeBuffer >>>> %d", bufidx);
    if (bufidxInput >= 0) {
        // 获取buffer的索引
        size_t out_size;

        uint8_t *inputBuf = AMediaCodec_getInputBuffer(audioCodec, bufidxInput, &out_size);
        if (inputBuf != nullptr && buf_size <= out_size) {
            // 将待解码的数据copy到硬件中
            memcpy(inputBuf, data, buf_size);

            int64_t pts = getCurrentTime() - audioPresentationTimeUs;

            media_status_t status = AMediaCodec_queueInputBuffer(audioCodec, bufidxInput, 0, buf_size, pts,0);
           //ALOGE("status >>>> %d ", status);
        }
    }


    return 0;
}

int _MEDIA_RECORD::startRecord() {
    audioPresentationTimeUs = getCurrentTime();
    videoPresentationTimeUs = getCurrentTime();
    start();

    if (!status) {
        status = true;
    }

    return 0;
}

int _MEDIA_RECORD::stopRecord() {

    AMediaMuxer_stop(muxer);
    AMediaMuxer_delete(muxer);
    if (status) {
        status = false;
    }
    return 0;
}

int _MEDIA_RECORD::release() {

    AMediaMuxer_delete(muxer);

    return 0;
}

void _MEDIA_RECORD::drainVideoEncoder() {

    AMediaCodecBufferInfo bufferInfo;

    ssize_t bufidx = AMediaCodec_dequeueOutputBuffer(videoCodec, &bufferInfo, 0);
    //ALOGE("AMediaCodec_dequeueOutputBuffer >>>>> %d", bufidx1);

    if (bufidx == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {

        //ALOGE("AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED");
        videoTrack = AMediaMuxer_addTrack(muxer, AMediaCodec_getOutputFormat(videoCodec));
        //ALOGE("media_record ---> init --->videoTrack >> %d", videoTrack );
        trackNum++;
        if (trackNum == TOTAL_TRACK) {
            media_status_t mediaMuxerStatus = AMediaMuxer_start(muxer);
            //ALOGE("media_record ---> init ---> mediaMuxerStatus >> %d", mediaMuxerStatus );
        }
    } else if (bufidx == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {

        //ALOGE("AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED");

    } else if (bufidx >= 0 && (bufferInfo.flags & AMEDIACODEC_BUFFER_FLAG_CODEC_CONFIG) == 0 && bufferInfo.presentationTimeUs != 0) {

        size_t outsize;

        uint8_t* outputBuf = AMediaCodec_getOutputBuffer(videoCodec, bufidx, &outsize);

        static FILE *file = nullptr;

        if (file == nullptr) {
            file = fopen("/sdcard/test111.h264", "w");
        }

        fwrite(outputBuf, bufferInfo.size, 1, file);

        if (outputBuf != nullptr) {
            ALOGE("drainVideoEncoder -> bufferInfo -> offset -> %d -> size -> %d -> presentationTimeUs -> %lld -> flags -> %d",bufferInfo.offset, bufferInfo.size, bufferInfo.presentationTimeUs, bufferInfo.flags);
            //fwrite(outputBuf, bufferInfo.size, 1, videoFile );
            media_status_t muxerWriteStatus = AMediaMuxer_writeSampleData(muxer, videoTrack, outputBuf, &bufferInfo);
            //ALOGE("drainVideoEncoder -----> muxerWriteStatus ---> %d" , muxerWriteStatus);
        }

        AMediaCodec_releaseOutputBuffer(videoCodec, bufidx, bufferInfo.size != 0);

    } else {
        //ALOGE("AMediaCodec_dequeueOutputBuffer > default");

    }
}

void _MEDIA_RECORD::drainAudioEncoder() {

    AMediaCodecBufferInfo bufferInfo;

    ssize_t bufidx = AMediaCodec_dequeueOutputBuffer(audioCodec, &bufferInfo, 0);
    //ALOGE("AMediaCodec_dequeueOutputBuffer >>>>> %d", bufidx1);

    if (bufidx == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {

        //ALOGE("AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED");
        audioTrack = AMediaMuxer_addTrack(muxer, AMediaCodec_getOutputFormat(audioCodec));
        //ALOGE("media_record ---> init --->audioTrack >> %d", audioTrack );
        trackNum++;
        if (trackNum == TOTAL_TRACK) {
            media_status_t mediaMuxerStatus = AMediaMuxer_start(muxer);
            //ALOGE("media_record ---> init ---> mediaMuxerStatus >> %d", mediaMuxerStatus );
        }
    } else if (bufidx == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {

        //ALOGE("AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED");

    } else if (bufidx >= 0 && (bufferInfo.flags & AMEDIACODEC_BUFFER_FLAG_CODEC_CONFIG) == 0 && bufferInfo.presentationTimeUs != 0) {

        size_t outsize;

        uint8_t* outputBuf = AMediaCodec_getOutputBuffer(audioCodec, bufidx, &outsize);

        if (outputBuf != nullptr) {

            //ALOGE("drainAudioEncoder -> bufferInfo -> offset -> %d -> size -> %d -> presentationTimeUs -> %lld -> flags -> %d",bufferInfo.offset, bufferInfo.size, bufferInfo.presentationTimeUs, bufferInfo.flags);
            AMediaMuxer_writeSampleData(muxer, audioTrack, outputBuf, &bufferInfo);
        }

        AMediaCodec_releaseOutputBuffer(audioCodec, bufidx, bufferInfo.size != 0);

    } else {
        //ALOGE("AMediaCodec_dequeueOutputBuffer > default");

    }

}

void _MEDIA_RECORD::run() {

    while (status) {
        drainVideoEncoder();
        drainAudioEncoder();
    }

}









